#include "bsp_flash.h"

/*
************************************************************************
*	函 数 名: BSP_Flash_Init
*	\param [in]  u8FreqCfg       FLASH编程时钟频率配置(根据HCLK的频率选择配置值)：
**                               1      - 4MHz;
**                               2      - 8MHz;
**                               4      - 16MHz;
**                               6      - 24MHz;
**                               8      - 32MHz;
**                               12     - 48MHz;
**                               other   -  无效值
*	返 回 值: void
*	说    明: 确保初始化正确执行后方能进行FLASH编程操作
************************************************************************
*/
void BSP_Flash_Init(uint8_t FreqCfg)
{    
    while(Ok != Flash_Init(FreqCfg, TRUE));  
}

/**
 *****************************************************************************
 ** \brief 从FLASH地址读一个字节
 **
 **
 ** \param 1 : Addr 地址
 ** 
 ** \retval   void                                  
 *****************************************************************************/
uint8_t BSP_Flash_ReadByte(uint32_t Addr)
{	
	return (*((unsigned char *)(Addr)));
}


/**
 *****************************************************************************
 ** \brief 从FLASH地址读一个字
 **
 **
 ** \param 1 : Addr 地址
 ** 
 ** \retval   void                                  
 *****************************************************************************/
uint32_t BSP_Flash_ReadWord(uint32_t Addr)
{	
	return (*((int *)(Addr)));
}

/**
 *************************************************************************
 ** \brief 从FLASH 写一个半字
 **
 **
 ** \param 1 : addr 地址  2：数据
 ** 
 ** \retval   void                              
 **************************************************************************/
void BSP_Flash_WriteHalfWord(uint32_t addr, uint16_t data)
{
    Flash_WriteHalfWord(addr,data);
}

/**
 ***********************************************************************
 ** \brief  Flash 写一个字
 **
 **
 ** \param 1 : addr 地址   2： data 数据
 ** 
 ** \retval   void                                
 ***********************************************************************/

void  BSP_Flash_WriteWord(uint32_t addr,uint32_t data)
{
	Flash_WriteWord(addr,data);		
}


/**
 *************************************************************************
 ** \brief 从FLASH 某个扇区遍历查询空的地址
 **
 **
** \param 1 : Addr 地址  2：addr_jump累加间隔(以Byte为单位)
 ** 
 ** \retval   返回扇区内的偏移量                                  
 **************************************************************************/
uint32_t BSP_Flash_Sector_Seek(uint32_t Addr, uint8_t addr_jump)
{	
	for( int i = 0; i< FLASH_SECTOR_SIZE ;i+= addr_jump)
	{
		if( (BSP_Flash_ReadByte(Addr+i) == 0xff) && (BSP_Flash_ReadByte(Addr+i+1) == 0xff))
		{
       		return  Addr+i;
		}
	}
	return  (Addr + FLASH_SECTOR_SIZE);
}
	

/**
 ***********************************************************************
 ** \brief 按字节读取一片flash,长度为Size个字节
 **
 **
 ** \param 1 : Addr 地址  2： *ReadBuff 接收数据指针  3：数据长度
 ** 
 ** \retval   void                                  
 ***********************************************************************/
void BSP_Flash_ReadBytes(uint32_t Addr, uint8_t *ReadBuff, uint32_t ByteLength)
{
	memcpy(ReadBuff, (uint8_t *)Addr, ByteLength);
	/*
	for (i = 0; i < u32ByteLength; i++)
	{
			pu8ReadBuff[i] = *((unsigned char *)(u32Addr+i));
	}
	*/
}


/*
************************************************************************
*	函 数 名: Flash_CheckBlank
*	形    参：void
*	返 回 值: void
*	说    明: flash一个扇区读检查空
************************************************************************
*/
boolean_t BSP_Flash_CheckBlank(uint32_t addr)
{
	uint32_t i = 0;  
	uint32_t temp = 0; 
	for(i = 0; i < 128; i++)
	{ 
		temp = *(volatile uint32_t *)(addr + i*4);
		if(temp != 0xFFFFFFFF)
		{
			return FALSE;
		}
	}
	return TRUE;
}


/*
************************************************************************
*	函 数 名: Flash_Write_Sector
*	形    参： void
*	返 回 值: void
*	说    明: 写满一个扇区的数据,用于升级
			  调用前扇区已经擦除！！
************************************************************************
*/
en_result_t  BSP_Flash_Write_Sector(uint32_t startaddr,uint8_t *buf)
{		
	en_result_t W_result = Flash_WriteBytes(startaddr, buf, FLASH_SECTOR_SIZE);
	return W_result;
}


void BSP_Flash_Sector_Clear(uint32_t sector_addr)
{
   Flash_SectorErase(sector_addr);
}


void BSP_Flash_WriteBytes(uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite)	
{
	
  	uint8_t HCFLASH_BUF[FLASH_SECTOR_SIZE];  //最多是512字节 
	
 	uint32_t secpos;	    //扇区地址
	uint16_t secoff;	    //扇区内偏移地址
	uint16_t secremain;   //扇区内剩余地址   
 	uint16_t i;    
	uint32_t offaddr; 
  
	offaddr = WriteAddr;
	
	secpos = offaddr/FLASH_SECTOR_SIZE;			//扇区地址  512 华大单片机
	
	secoff = (offaddr%FLASH_SECTOR_SIZE);		//在扇区内的偏移
	
	secremain = FLASH_SECTOR_SIZE - secoff;		//扇区剩余空间大小  
	
	if(NumToWrite <= secremain)
	{		
		 secremain = NumToWrite;//不大于该扇区范围
	}
	while(1) 
	{		 
		BSP_Flash_ReadBytes(offaddr, HCFLASH_BUF, FLASH_SECTOR_SIZE);//读出整个扇区的内容
				
		for( i = 0; i < secremain; i++)//校验数据
		{
			if(HCFLASH_BUF[secoff+i]!=0XFF)break;//需要擦除  	  
		}
		if(i < secremain)//需要擦除.说明中途 判断错误跳出来的
		{			
				Flash_SectorErase(secpos*FLASH_SECTOR_SIZE);//擦除这个扇区
				for( i = 0; i < secremain; i++)//复制
				{
						HCFLASH_BUF[i+secoff] = pBuffer[i];	  
				}		
				Flash_WriteBytes(secpos*FLASH_SECTOR_SIZE,HCFLASH_BUF, FLASH_SECTOR_SIZE);//写入整个扇区,把读出来数据也擦除  
		}
		else 
		{
				Flash_WriteBytes(WriteAddr,pBuffer, secremain);//写入整个扇区  ;写已经擦除了的,直接写入扇区剩余区间. 	
		}
			
		if(NumToWrite == secremain)
		{
				break;//写入结束了
		}
		else//写入未结束
		{
				secpos++;				//扇区地址增1
				secoff = 0;				//偏移位置为0 	 
				pBuffer += secremain;  	//指针偏移
				WriteAddr += secremain;	//写地址偏移	   
				NumToWrite -= secremain;	//字节
				if(NumToWrite>(FLASH_SECTOR_SIZE))
				{
						secremain = FLASH_SECTOR_SIZE;//下一个扇区还是写不完
				}
				else
				{
						secremain = NumToWrite;//下一个扇区可以写完了		
				}					
		}	
	}
}



